package com.chat.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chat.domain.converter.UserConverter;
import com.chat.domain.dto.ChatQueryDTO;
import com.chat.domain.dto.LoginDTO;
import com.chat.domain.dto.UserPasswordDTO;
import com.chat.domain.dto.UserProfileDTO;
import com.chat.domain.pojo.Chat;
import com.chat.domain.pojo.Message;
import com.chat.domain.pojo.User;
import com.chat.excpetion.CustomException;
import com.chat.mapper.UserMapper;
import com.chat.service.UserService;
import com.chat.util.ResultCodeEnum;
import com.chat.util.SecurityHolderUtil;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author wb
 * @since 2024-08-19
 */

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public List<Integer> getGroupIdsById(Integer userId) {
        ChatQueryDTO chatQuery = new ChatQueryDTO();
        chatQuery.setUserId(userId);

        return this.getChats(chatQuery)
                // 获取所有聊天列表
                .stream()
                // 过滤群聊
                .filter(chat -> chat.getChatType() == 2)
                // 收集群聊ID
                .map(Chat::getReceiverId)
                // 转换成列表
                .collect(Collectors.toList());
    }

    @Override
    public List<Chat> getChats(ChatQueryDTO chatQueryDTO) {
        Integer userId = chatQueryDTO.getUserId();

        // 获取聊天列表
        List<Chat> chats = baseMapper.getChatsById(userId);
        List<Chat> groupChats = baseMapper.getGroupIdsById(userId);
        chats.addAll(groupChats);

        // 为每个聊天设置聊天ID和消息列表
        chats.forEach(chat -> {
            if (chat.getChatType() == 1) {
                chat.setChatId(getChatKey(userId, chat.getReceiverId()));
                Object object = redisTemplate.opsForValue().get(getUnreadCountKey(userId, chat.getReceiverId(), false));
                if(object!=null){
                    chat.setCount(Integer.valueOf(object.toString()));
                }

            } else {
                Object object = redisTemplate.opsForValue().get(getUnreadCountKey(userId, chat.getReceiverId(), true));
                if(object!=null){
                    chat.setCount(Integer.valueOf(object.toString()));
                }
                chat.setChatId("group-" + chat.getReceiverId());
            }
        });

        return chats;
    }
    private String getUnreadCountKey(Integer receiverId, Integer chatId, boolean isGroup) {
        return isGroup ? "unread:group:" + receiverId + ":" + chatId : "unread:private:" + receiverId + ":" + chatId;
    }

    @Override
    public Boolean login(LoginDTO loginDTO, HttpSession session) {
        // 根据用户名称查询用户
        User user = baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, loginDTO.getUsername()));

        // 判断用户是否存在
        if (ObjectUtil.isEmpty(user)) {
            throw new CustomException(ResultCodeEnum.USERNAME_NOT_EXISTS);
        }

        // 判断密码是否正确
        if (!user.getPassword().equals(loginDTO.getPassword())) {
            throw new CustomException(ResultCodeEnum.PASSWORD_ERROR);
        }

        // 将用户信息保存到 session 中
        session.setAttribute("user", user);

        return true;
    }

    @Override
    public Boolean updateProfile(UserProfileDTO userProfileDTO, HttpSession session) {
        User user = UserConverter.INSTANCE.toEntity(userProfileDTO);
        return super.updateById(user);
    }

    @Override
    public Boolean updatePassword(UserPasswordDTO userPasswordDTO, HttpSession session) {
        User user = SecurityHolderUtil.getUser(session);

        // 判断旧密码是否正确
        if (!user.getPassword().equals(userPasswordDTO.getOldPwd())) {
            throw new CustomException(ResultCodeEnum.OLD_PASSWORD_ERROR);
        }

        // 设置新密码
        user.setPassword(userPasswordDTO.getNewPwd());

        return super.updateById(user);
    }

    @Override
    public void saveMessage(Message message) {
        String chatId = message.getChatId();

        // 保存30天
        redisTemplate.expire(chatId,30, TimeUnit.DAYS);

        // 将聊天信息保存至 redis
        redisTemplate.opsForZSet().add(chatId, message, message.getTime().getTime());
    }

    @Override
    public Chat getChatInfo(String chatId, HttpSession session) {
        ChatQueryDTO chatQueryDTO = new ChatQueryDTO();
        chatQueryDTO.setUserId(SecurityHolderUtil.getUserId(session));

        List<Chat> chats = this.getChats(chatQueryDTO);

        // 根据聊天ID查询聊天
        Chat c =  chats.stream()
                .filter(chat -> chat.getChatId().equals(chatId))
                .findFirst()
                .orElse(null);

        if(c == null){
            return null;
        }

        if(c.getChatType() == 2){
            c.setMembers(getMember(chatId));
        }

        c.setMessages(getMessages(chatId));

        return c;
    }

    @Override
    public Boolean deleteChat(String chatId) {
        return null;
    }

    @Override
    public Boolean batchDeleteChat(String str) {
        return null;
    }

    /**
     * 获取聊天记录的 key
     *
     * @param sender   发送人
     * @param receiver 接收人
     * @return key
     */
    private String getChatKey(Integer sender, Integer receiver) {
        if (sender.compareTo(receiver) < 0) {
            return "user-" + sender + "-" + receiver;
        } else {
            return "user-" + receiver + "-" + sender;
        }
    }


    /**
     * 获取聊天记录
     *
     * @param chatId 聊天ID
     * @return 聊天记录
     */
    private Set<Message> getMessages(String chatId) {
        if (!redisTemplate.hasKey(chatId)) {
            return null;
        }

        return redisTemplate.opsForZSet().range(chatId, 0, -1);
    }

    /**
     * 获取聊天成员
     *
     * @param chatId 聊天ID
     * @return 聊天成员
     */
    private List<User> getMember(String chatId) {
        if (chatId.contains("user")) {
            return null;
        } else {
            String groupId = chatId.substring(chatId.lastIndexOf("-") + 1);
            return baseMapper.getGroupMember(groupId);
        }
    }
}
